package broadcast

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
)

const (
	// PacketCommandSize 命令长度
	PacketCommandSize = 4 //MainId(uint16) + SubId(uint16)
	// PacketHeaderSize 包体头部长度
	PacketHeaderSize = 7 //Msgflag(uint16) + MsgType(uint8) + MsgSize(uint16)
	// PacketedHeadSize 最大长度
	PacketedHeadSize = 9 //Msgflag(uint16) + MsgType(uint8) + MsgSize(uint16) + MainId(uint16) + SubId(uint16)
	//MaxPacketSize     = 1024 * 8 //包的长度
)

// PacketStream 封包流
type PacketStream interface {
	Read() (*Packet, error)
	Write(pkt *Packet) error
	Close() error
	GetRemoteAddr() string
	ID() int
	WriteBytes(data []byte) error
}

// Stream 流
type Stream struct {
	id int
	conn    net.Conn
	encrypt bool
}

var (
	// ErrPacketTagNotMatch 标志没有匹配
	ErrPacketTagNotMatch = errors.New("ReadPacket: packet tag not match")
	// ErrPacketDataSizeInvalid 长度有问题
	ErrPacketDataSizeInvalid = errors.New("ReadPacket: packet crack, invalid size")
	// ErrPacketTooBig 包体太大
	ErrPacketTooBig = errors.New("ReadPacket: packet too big")
)

func (s *Stream) ID()int{
	return s.id
}

// 从socket读取1个封包,并返回
func (s *Stream) Read() (p *Packet, err error) {

	//读取包头
	headdata := make([]byte, PacketHeaderSize)
	if _, err = io.ReadFull(s.conn, headdata); err != nil {
		return nil, err
	}
	//读取MsgTag
	msgTag := uint16(binary.BigEndian.Uint16(headdata[0:2]))

	//非法包
	if msgTag != msgTag {
		return nil, ErrPacketTagNotMatch
	}

	//读取包类型
	msgType := headdata[2]

	//读取整包大小
	fullSize := uint32(binary.BigEndian.Uint32(headdata[3:7]))

	dataSize := fullSize - PacketHeaderSize
	if dataSize < 0 {
		return nil, ErrPacketDataSizeInvalid
	}

	//读取加密数据
	packData := make([]byte, dataSize)
	if _, err = io.ReadFull(s.conn, packData); err != nil {
		return nil, err
	}

	//效验接收到的大小
	if packData == nil || dataSize != uint32(len(packData)) {
		return nil, err
	}

	p, err = ToDecryptPacket(packData, msgType)
	if err != nil {
		return nil, err
	}

	return p, nil
}

//将一个封包发送到socket
func (s *Stream) Write(pkt *Packet) (err error) {

	buffer := make([]byte, PacketHeaderSize)

	//写MsgTag
	binary.BigEndian.PutUint16(buffer[0:2], uint16(MsgTag))

	var userdata []byte
	msgtype := uint8(EncryptNone)
	if s.encrypt {
		userdata, msgtype = pkt.ToEncryptByteArray() //写MsgType 加密决定包类型
		buffer[2] = msgtype
	} else {
		userdata = pkt.ToByteArray()
	}

	//写MsgSize
	packetsize := len(userdata) + PacketHeaderSize
	binary.BigEndian.PutUint32(buffer[3:7], uint32(packetsize))

	//写数据
	buffer = append(buffer[:PacketHeaderSize], userdata...)


	if _, err = s.conn.Write(buffer); err != nil {
		return err
	}


	fmt.Println("send byte:",len(buffer))

	return nil
}

// GetRemoteAddr 获取ip地址
func (s *Stream) GetRemoteAddr() string {
	ipstring, _, _ := net.SplitHostPort(s.conn.RemoteAddr().String())
	return ipstring
}

// Close 关闭
func (s *Stream) Close() error {
	return s.conn.Close()
}

// 写入byte
func (s *Stream) WriteBytes(data []byte) error{
	return nil
}

var SteamID = 0

// NewPacketStream 封包流 relay模式: 在封包头有clientid信息
func NewPacketStream(conn net.Conn, encrypt bool) PacketStream {
	SteamID++
	return &Stream{
		id:SteamID,
		conn:    conn,
		encrypt: encrypt,
	}
}
